package com.igoal.service.fu.xmas;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.context.SecurityContextHolder;

import com.igoal.service.fu.MonitoredDiskFileItemFactory;
import com.igoal.service.fu.UploadListener;
import com.igoal.utils.ConvertUtils;
import com.igoal.utils.ImageUtils;
import com.igoal.web.Constants;

public class ImageUploadServlet extends HttpServlet{

	private static final long serialVersionUID = -4217538129610651567L;
	
	private static final String TEMP_FOLDER_PARAM = "tempFolder";
	private static final String DES_FOLDER_PARAM = "desFolder";
	
	private static final Log logger = LogFactory.getLog(ImageUploadServlet.class);
	
	private File tmpDir;
	private File destinationDir;
	private Map<String, String> allowExtensions;
	private long maxFileSize;
	
	@Override
	public void init(ServletConfig config) throws ServletException {
		super.init(config);
		String tmpFolderName = config.getInitParameter(TEMP_FOLDER_PARAM);
		tmpDir = new File(tmpFolderName);
		if (!tmpDir.exists()) {
			tmpDir.mkdirs();
		} else if (!tmpDir.isDirectory()) {
			throw new ServletException(tmpFolderName + " is not a directory");
		}

		String desFolderName = config.getInitParameter(DES_FOLDER_PARAM);
		String rootPath = getServletContext().getRealPath("/");
		File rootFolder = (new File(rootPath)).getParentFile();
		destinationDir = new File(rootFolder, desFolderName);
		if (!destinationDir.exists()) {
			destinationDir.mkdirs();
		} else if (!destinationDir.isDirectory()) {
			throw new ServletException(desFolderName + " is not a directory");
		}

		allowExtensions = new HashMap<String, String>();
		String allowExtsConfig = config.getInitParameter("allowExtensions");
		if (allowExtsConfig != null) {
			String[] allowExts = allowExtsConfig.split(",");
			for (String allowExt : allowExts) {
				if (!allowExtensions.containsKey(allowExt)) {
					allowExtensions.put(allowExt, allowExt);
				}
			}
		}

		maxFileSize = ConvertUtils.toLong(config.getInitParameter("maxFileSize"),4 * 1024 * 1024);
	}
	
	private boolean isImage(String contentType) {
		if (contentType == null || "".equals(contentType.trim()))
			return false;
		return Pattern.compile("image/[a-zA-Z0-9]+").matcher(contentType)
				.matches();
	}

	private boolean isSupportImageExtenstion(final String contentType) {
		if (!isImage(contentType))
			return false;

		String imageExt = getImageExtension(contentType);
		String allowExt = allowExtensions.get(imageExt);

		return allowExt != null;
	}

	private String getImageExtension(String imageType) {
		if (!isImage(imageType))
			return null;

		String imagePrefix = "image/";
		String imageExtension = imageType.substring(imagePrefix.length());
		return imageExtension;
	}

	private String getSaveImageExtension(String imageExt) {
		if ("png".equals(imageExt) || "x-png".equalsIgnoreCase(imageExt)) {
			return "png";
		}else if ("jpg".equals(imageExt) || "pjpeg".equalsIgnoreCase(imageExt)) {
			return "jpg";
		}else if ("bmp".equals(imageExt)) {
			return "bmp";
		}

		return imageExt;
	}
	
	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		boolean isMultipart = ServletFileUpload.isMultipartContent(request);
		boolean success = true;
		String imageName = "";
		String username = SecurityContextHolder.getContext().getAuthentication().getName();
		FileItem imageItem = null;
		String imageType = null;
		
		if (!isMultipart) {
			success = false;
		} else {
			logger.info("User [" + username + "] has requested upload an image.");
			UploadListener listener = new UploadListener(request, 30);
			DiskFileItemFactory factory = new MonitoredDiskFileItemFactory(listener);;
			factory.setSizeThreshold(1 * 1024 * 1024); // 1 MB
			ServletFileUpload upload = new ServletFileUpload(factory);
			upload.setSizeMax(maxFileSize);

			List items = null;
			try {
				items = upload.parseRequest(request);
				Iterator itr = items.iterator();
				while (itr.hasNext()) {
					FileItem item = (FileItem) itr.next();

					if (logger.isDebugEnabled()) {
						logger.debug("Submitted form item name: "
								+ item.getFieldName());
					}

					if (!item.isFormField()) {
						try {
							String itemName = item.getFieldName();
							if ("image".equals(itemName)) {
								imageItem = item;
								logger.debug("File type is " + item.getContentType());
								imageType = item.getContentType();
							}
						} catch (Exception e) {
							success = false;
							logger.error(e);
						}
					}
				}
			} catch (FileUploadException e) {
				logger.error(e);
				success = false;
			}

			String desWithUsername = destinationDir + File.separator + username;
			if (success && isSupportImageExtenstion(imageType)) {
				long timeStamp = new Date().getTime();
				String imageExt = getImageExtension(imageType);
				imageExt = getSaveImageExtension(imageExt);
				imageName = timeStamp + imageItem.getName().hashCode() + "."
						+ imageExt;
				if (logger.isDebugEnabled()) {
					logger.debug("Saving image from user uploaded: "
							+ desWithUsername + File.separator + imageName
							+ "...");
				}
				
				logger.info("Saving image request from user: " + username);
				imageName = saveEntryImage(desWithUsername, imageName, imageItem);
				success = imageName != null;
			}

			if (success) {
				StringBuffer xmlResponse = new StringBuffer("<image>");
				xmlResponse.append(getServletConfig().getInitParameter(
						DES_FOLDER_PARAM));
				xmlResponse.append("/").append(username).append("/").append(
						imageName);
				xmlResponse.append("</image>");
				if (logger.isDebugEnabled()) {
					logger.debug("Saved file tag: " + xmlResponse);
				}
				PrintWriter out = response.getWriter();
				response.setContentType("text/xml");
				out.print(xmlResponse.toString());
				out.close();
			} else {
				response.sendError(HttpServletResponse.SC_BAD_REQUEST);
			}
		}
	}
	
	private String saveEntryImage(String desWithUsername, String imageName,
			FileItem imageItem) {
		try {
			float standardRatio = (float)Constants.IMAGE_CARD_WIDTH/(float)Constants.IMAGE_CARD_HEIGHT;
			
			File userDirectory = new File(desWithUsername);
			if (!userDirectory.exists()) {
				userDirectory.mkdirs();
			}

			File savedFile = new File(tmpDir, imageName);
			File finalFile = new File(desWithUsername, imageName);

			// save upload image to temp folder
			imageItem.write(savedFile);

			int[] fileSize = new int[2]; 
			ImageUtils.getImageSize(savedFile.getAbsolutePath(), fileSize);
			float imageRatio = (float)fileSize[0]/(float)fileSize[1];
			
			String output = "";
			if(imageRatio > standardRatio){
				if(fileSize[0] > Constants.IMAGE_CARD_WIDTH){
					output = ImageUtils.scaleXmasImage(savedFile.getAbsolutePath(), finalFile.getAbsolutePath(), true);
				}
			}else if(imageRatio < standardRatio){
				if(fileSize[1] > Constants.IMAGE_CARD_HEIGHT){
					output = ImageUtils.scaleXmasImage(savedFile.getAbsolutePath(), finalFile.getAbsolutePath(), false);
				}
			}else{
				if(fileSize[0] > Constants.IMAGE_CARD_WIDTH){
					output = ImageUtils.scaleXmasImage(savedFile.getAbsolutePath(), finalFile.getAbsolutePath(), true);
				}else{
					ImageUtils.copyFile(savedFile, finalFile, true);
					output = savedFile.getAbsolutePath();
				}
			}
			
//			if(fileSize[0] > WebPreferences.IMAGE_CARD_WIDTH){
//				// resize image
//				output = ImageUtils.scaleXmasImage(savedFile.getAbsolutePath(), finalFile.getAbsolutePath());
//			}else{
//				ImageUtils.copyFile(savedFile, finalFile, true);
//				output = savedFile.getAbsolutePath();
//			}
			
			int lastSplashPos = output.lastIndexOf(File.separator);
			if(lastSplashPos <= 0)
				return null;
			
			output = output.substring(lastSplashPos+1);
			return output;
		} catch (Exception e) {
			logger.error(e);
			return null;
		}
	}
}
